/**
 * Copyright (c) 2020 Coder League
 * All rights reserved.
 *
 * File：AreaService.java
 * History:
 *         2020年12月21日: Initially created, Chrise.
 */
package club.coderleague.cfss.service.area;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.validation.ValidationException;

import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import club.coderleague.cfss.dao.AreaDao;
import club.coderleague.cfss.domain.entities.Areas;
import club.coderleague.cfss.domain.enums.EntityState;
import club.coderleague.cfss.exceptions.RequestProcessInfoException;
import club.coderleague.cfss.exceptions.RequestProcessWarnException;
import club.coderleague.cfss.util.CommonUtil;

/**
 * 区域服务。
 * @author Chrise
 */
@Service
public class AreaService {
	@Autowired
	private AreaDao areaDao;
	
	/**
	 * 分页查询区域。
	 * @author Chrise 2020年12月21日
	 * @param isrecycle 是否回收站。
	 * @param keyword 关键字。
	 * @return 分页区域数据。
	 */
	public List<Areas> findAllByParamsMap(boolean isrecycle, String keyword) {
		return this.areaDao.findAllByParamsMap(isrecycle, keyword);
	}
	
	/**
	 * 查询所有区域。
	 * @author Chrise 2020年12月21日
	 * @return 区域数据。
	 */
	public List<Map<String, Object>> findAll() {
		return this.areaDao.findAllMap();
	}
	
	/**
	 * 根据区域主键查询区域。
	 * @author Chrise 2020年12月21日
	 * @param entityid 区域主键。
	 * @return 区域数据。
	 */
	public Areas findOneByEntityid(Long entityid) {
		if (entityid == null) {
			throw new ValidationException("区域主键不能为空");
		}
		return this.areaDao.getOne(entityid);
	}
	
	/**
	 * 新增区域。
	 * @author Chrise 2020年12月21日
	 * @param areas 区域数据。
	 */
	public void insert(Areas areas) {
		if (areas.getParentarea() != null && areas.getParentarea() == -1) {
			areas.setParentarea(null);
		}
		if (this.areaDao.existsByAreanameAndParentareaNotEntityid(areas.getAreaname(), areas.getAreacode(), areas.getParentarea(), null)) {
			throw new RequestProcessInfoException("区域名称或编码已存在");
		}
		areas.setEntitystate(EntityState.VALID.getValue());
		this.areaDao.save(areas);
	}
	
	/**
	 * 更新区域。
	 * @author Chrise 2020年12月21日
	 * @param areas 区域数据。
	 */
	public void update(Areas areas) {
		if (areas.getEntityid() == null) {
			throw new RequestProcessWarnException("区域主键不能为空");
		}
		if (areas.getParentarea() != null && areas.getParentarea() == -1) {
			areas.setParentarea(null);
		}
		if (this.areaDao.existsByAreanameAndParentareaNotEntityid(areas.getAreaname(), areas.getAreacode(), areas.getParentarea(), areas.getEntityid())) {
			throw new RequestProcessInfoException("区域名称或编码已存在");
		}
		Areas areasSource = this.areaDao.getOne(areas.getEntityid());
		areasSource.setAreaname(areas.getAreaname());
		areasSource.setAreacode(areas.getAreacode());
		areasSource.setAreadesc(areas.getAreadesc());
		areasSource.setParentarea(areas.getParentarea());
	}
	
	/**
	 * 更新区域状态。
	 * @author Chrise 2020年12月21日
	 * @param entityids 区域主键。
	 * @param entitystate 实体状态。
	 * @param isdistinct 是否去重。
	 */
	public void updateEntitystate(String entityids, Integer entitystate, boolean isdistinct) {
		if (StringUtils.isBlank(entityids)) {
			throw new ValidationException("区域主键不能为空");
		}
		for (String entityid : entityids.split(",")) {
			Areas areas = this.areaDao.getOne(Long.parseLong(entityid));
			if (areas == null) {
				continue;
			}
			if (isdistinct && this.areaDao.existsByAreanameAndParentareaNotEntityid(areas.getAreaname(), areas.getAreacode(), areas.getParentarea(), areas.getEntityid())) {
				throw new RequestProcessInfoException("区域名称或编码已存在");
			}
			areas.setEntitystate(entitystate);
		}
	}
	
	/**
	 * 导入区域。
	 * @author Chrise 2021年3月12日
	 * @param file 导入文件。
	 * @return 导入结果。
	 * @throws IOException IO 异常。
	 */
	public Map<String, Object> execImportAreas(MultipartFile file) throws IOException {
		if (file == null) throw new IOException("file not found.");
		
		String name = file.getOriginalFilename();
		if (CommonUtil.isEmpty(name) || !name.endsWith(".txt")) throw new IOException("invalid file type.");
		
		String line = null;
		int success = 0, ignore = 0;
		BufferedReader reader = new BufferedReader(new InputStreamReader(file.getInputStream(), "UTF-8"));
		while ((line = reader.readLine()) != null) {
			String[] data = line.split(",");
			
			Long parentarea = null;
			int level = Integer.valueOf(data[0]);
			if (level > 0) {
				String parentpre = data[2].substring(0, level * 2);
				String parentcode = StringUtils.rightPad(parentpre, 12, "0");
				parentarea = this.areaDao.queryIdByCode(parentcode);
				if (parentarea == null) {
					ignore ++;
					continue;
				}
			}
			
			if (this.areaDao.existsByAreanameAndParentareaNotEntityid(data[1], data[2], parentarea, null)) {
				ignore ++;
				continue;
			}
			
			Areas area = new Areas(EntityState.VALID.getValue(), data[1], parentarea, data[2], data[1]);
			this.areaDao.save(area);
			success ++;
		}
		
		Map<String, Object> result = new HashMap<String, Object>();
		result.put("success", success);
		result.put("message", "成功 " + success + " 条，忽略 " + ignore + " 条！");
		return result;
	}
	
	/**
	 * 根据区域主键查询区域。
	 * @author Chrise 2020年12月21日
	 * @param entityid 区域主键。
	 * @return 区域数据。
	 */
	public Map<String, Object> findMapByEntityid(Long entityid) {
		if (entityid == null) {
			throw new ValidationException("区域主键不能为空");
		}
		return this.areaDao.findMapByEntityid(entityid);
	}
	
	/**
	 * 获取用于移动端选择的区域。
	 * @author Chrise 2020年12月26日
	 * @param parent 父级区域。
	 * @return 区域数据。
	 */
	public List<Map<String, Object>> getAreasForMobileSelect(Long parent) {
		return this.areaDao.getAreasForMobileSelect(parent);
	}
}
